O objetivo desse trabalho é analisar o banco de dados “Spotify_1Million_Tracks”, realizando uma análise descritiva deles, e analisar os métodos de cluster, ajustando dendrogramas para suas observações e variáveis. Além disso, também observar o efeito do número de clusters no método k-means para o banco.
O banco contém dados de 1 milhão de músicas que foram extraídos do
Spotify utilizando a biblioteca “Spotipy” do Python. Para cada música na
plataforma, o Spotify guarda dados para 13 parâmetros:
Danceability - Dançabilidade, o quão dançável é a música baseado no
ritmo, tempo e etc.
Valence - Valência, a positividade expressada pela música.
Energy - Energia, que representa a intensidade e atividade da música no
geral.
Tempo - O tempo estimado da música em BPM (batidas por minuto).
Loudness - O quão alta, ou barulhenta, é a música em decibéis.
Speechiness - A presença de fala na música.
Instrumentalness - A presença de instrumental na música.
Liveness - Detecção da presença de audiência.
Acousticness - Uma métrica do quão acústica é a música.
Mode - A escala em que está a música, 1= Maior e 0 = Menor.
Duration - A duração da música em milisegundos.
Time Signature - O compasso da música por 4.
Key - O tom que a música foi escrita
Popularity - Uma métrica de popularidade da faixa
O banco guarda esses parâmetros juntamente com artista, gênero musical e o id da faixa
dados_originais <- read.csv("spotify_data.csv")
aux <- sample(1:nrow(dados_originais), size=nrow(dados_originais)*0.005)
dados <- dados_originais[aux,-c(1:4)]
dados2 <- dados[dados$year==2022,]
dados3 <- dados2[,-c(2,3,6,8,16)]
#variaveis categoricas: c(2,3,6,8,16)
library(dplyr)
library(ggplot2)
library(GGally)
library(corrplot)
library(factoextra)
library(gridExtra)
library(plotly)
ggplotly(ggplot(data = dados2, aes(x = popularity)) +
geom_histogram(color = "black", fill = "steelblue") +
labs(x = 'Popularidade'))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
ggplotly(ggplot(data = dados2, aes(x = year)) +
geom_bar(color = "black", fill = "steelblue") +
labs(x = 'Ano'))
ggplotly(ggplot(data = dados2, aes(x = danceability)) +
geom_histogram(color = "black", fill = "steelblue") +
labs(x = 'Dançabilidade',y="Frequencia"))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
ggplotly(ggplot(data = dados2, aes(x = energy)) +
geom_histogram(color = "black", fill = "steelblue") +
labs(x = 'Energia'),y="Frequencia")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
ggplotly(ggplot(data = dados2, aes(x = key)) +
geom_bar(color = "black", fill = "steelblue") +
scale_x_continuous(breaks=seq(0,11,by=1),labels = c("C","C#","D","D#","E","F","F#","G","G#","A","A#","B")) +
scale_y_continuous(breaks=seq(0,150000,by=25000),labels=c("0","25","50","75","100","125","150")) +
labs(x = 'Tom',y='Frequencia'))
ggplotly(ggplot(data = dados2, aes(x = loudness)) +
geom_histogram(color = "black", fill = "steelblue") +
scale_x_continuous(breaks=seq(15,60,by=5)) +
scale_y_continuous(breaks=seq(0,300000,by=50000),labels=c("0","50","100","150","200","250","300")) +
labs(x = 'Decibéis',y = 'Frequencia'))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
ggplotly(ggplot(data = dados2, aes(x = mode)) +
geom_bar(color = "black", fill = "steelblue") +
scale_x_continuous(breaks = c(0,1),labels = c("Menor","Maior")) +
scale_y_continuous(breaks=seq(0,700000,by=100000),labels=c("0","100","200","300","400","500","600","700")) +
labs(x = 'Escala',y = 'Frequencia'))
ggplotly(ggplot(data = dados2, aes(x = speechiness)) +
geom_histogram(color = "black", fill = "steelblue") +
scale_y_continuous(breaks=seq(0,600000,by=100000),labels=c("0","100","200","300","400","500","600")) +
labs(x = 'Fala',y = 'Frequencia'))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
ggplotly(ggplot(data = dados2, aes(x = acousticness)) +
geom_histogram(color = "black", fill = "steelblue") +
scale_y_continuous(breaks=seq(0,400000,by=100000),labels=c("0","100","200","300","400")) +
labs(x = 'Acusticidade',y="Frequencia"))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
ggplotly(ggplot(data = dados2, aes(x = instrumentalness)) +
geom_histogram(color = "black", fill = "steelblue") +
scale_y_continuous(breaks=seq(0,700000,by=100000),labels=c("0","100","200","300","400","500","600","700")) +
labs(x = 'Instrumentalidade',y="Frequencia"))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
ggplotly(ggplot(data = dados2, aes(x = liveness)) +
geom_histogram(color = "black", fill = "steelblue") +
scale_y_continuous(breaks=seq(0,300000,by=100000),labels=c("0","100","200","300")) +
labs(x="Presença de audiência",y="Frequencia"))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
ggplotly(ggplot(data = dados2, aes(x = valence)) +
geom_histogram(color = "black", fill = "steelblue") +
labs(x="Valência",y="Frequencia"))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
ggplotly(ggplot(data = dados2, aes(x = tempo)) +
geom_histogram(color = "black", fill = "steelblue") +
labs(x = 'Bpm',y='Frequencia'))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
ggplotly(ggplot(data = dados2, aes(x = duration_ms)) +
geom_histogram(color = "black", fill = "steelblue") +
xlim(c(0,1e+06)) +
labs(x = 'Duração',y="Frequencia"))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
ggplotly(ggplot(data = dados2, aes(x = time_signature)) +
geom_bar(color = "black", fill = "steelblue") +
scale_x_continuous(breaks=seq(0,7,by=1)) +
labs(x = 'Compasso',y="Frequencia"))
corrplot(cor(dados3))
A variável acousticness tem alta correlação negativa com as variáveis energy e loudness, indicando que músicas acústicas tendem a não serem energéticas e altas. A variável valence tem alta correlação positiva com a variável danceability, o que implica que músicas dançáveis são mais positivas. Também, temos correlações menores entre loudness e instrumentalness (negativa) e acousticness e tempo (negativa).
res.dist <- get_dist(dados3, method = "pearson") # Correlation-based distance method
fviz_dist(res.dist, lab_size = 8) # Visualize the dissimilarity matrix
res.dist2 <- get_dist(dados3, method = "euclidian") # Correlation-based distance method
fviz_dist(res.dist2, lab_size = 8) # Visualize the dissimilarity matrix
res.dist3 <- get_dist(dados3, method = "manhattan") # Correlation-based distance method
fviz_dist(res.dist3, lab_size = 8) # Visualize the dissimilarity matrix
res.dist4 <- get_dist(dados3, method = "minkowski") # Correlation-based distance method
fviz_dist(res.dist4, lab_size = 8) # Visualize the dissimilarity matrix
hc <- eclust(dados3, "hclust", hc_metric = "euclidean", hc_method = "ward.D", k=100)
## Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as
## of ggplot2 3.3.4.
## ℹ The deprecated feature was likely used in the factoextra package.
## Please report the issue at <]8;;https://github.com/kassambara/factoextra/issueshttps://github.com/kassambara/factoextra/issues]8;;>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
fviz_dend(hc, rect = TRUE, k=3, show_labels=FALSE)
A amostra apresenta clara distinção para 2 ou 3 grupos.
var_cat <- dados2[,c(3,6,8,16)]
for (i in (1:4)) {
var_cat[, i] <- factor(var_cat[, i])
}
library(ClustOfVar)
## Warning: package 'ClustOfVar' was built under R version 4.2.3
tree <- hclustvar(dados3, var_cat)
plot(tree)
# normalização das variáveis
dadosNorm <- as.data.frame(scale(dados3))
set.seed(1234)
dados_k2 <- kmeans(dadosNorm, centers = 3)
dados_k2$size
## [1] 59 120 117
dados_k2$size/nrow(dados3)
## [1] 0.1993243 0.4054054 0.3952703
O primeiro cluster tem 187 (70%) observações, enquanto que o segundo tem 22 (8%) e o terceiro 59 (22%).
aggregate(dados3, by=list(dados_k2$cluster), mean)
## Group.1 popularity danceability energy loudness speechiness acousticness
## 1 1 28.86441 0.3243356 0.1644575 -21.305763 0.05147458 0.88079131
## 2 2 22.51667 0.5477583 0.8035750 -6.636758 0.07143000 0.07726371
## 3 3 44.98291 0.6516496 0.6931026 -6.586000 0.12143419 0.29529011
## instrumentalness liveness valence tempo duration_ms
## 1 0.6667870 0.1436797 0.1777510 105.8589 187027.3
## 2 0.3516849 0.2444417 0.3671167 129.5817 266481.5
## 3 0.0489660 0.2046940 0.6127359 126.2038 185276.8
Estas foram as principais características de cada cluster:
Primeiro - Maior popularidade, dançabilidade, volume, positividade, tempo e duração. Também, esse grupo apresentou menor acusticidade, poucas letras e alta energia. Isso implica que a amostra apresenta um grupo de músicas mais populares, com maior volume, mais positivas e mais dançáveis, que também contém menos elementos acústicos.
Segundo - Menor popularidade, dançabilidade e instrumentalidade, bem como mais letras e mais “liveness” (aspectos de músicas performadas ao vivo).
Terceiro - Menor energia, volume, “liveness”, valence, tempo, duração e menos letras. Além de maior acusticidade e instrumentalidade. Esse grupo aparenta conter músicas mais tristes e acústicas.
# quantos clusters?
bss <- numeric()
wss <- numeric()
for(i in 1:10){
# For each k, calculate betweenss and tot.withinss
bss[i] <- kmeans(dadosNorm, centers=i)$betweenss
wss[i] <- kmeans(dadosNorm, centers=i)$tot.withinss
}
# Between-cluster sum of squares vs Choice of k
p3 <- qplot(1:10, bss, geom=c("point", "line"),
xlab="Number of clusters", ylab="Between-cluster sum of squares") +
scale_x_continuous(breaks=seq(0, 10, 1)) +
theme_bw()
# Total within-cluster sum of squares vs Choice of k
p4 <- qplot(1:10, wss, geom=c("point", "line"),
xlab="Number of clusters", ylab="Total within-cluster sum of squares") +
scale_x_continuous(breaks=seq(0, 10, 1)) +
theme_bw()
# Subplot
grid.arrange(p3, p4, ncol=2)
A partir das somas de quadrados, 2 ou 3 clusters seriam ideais. O ganho da inclusao de mais clusters é em geral similar, com exceção da diferença entre 6 e 7 clusters.